import itertools
from typing import Tuple

import numpy as np
import pandas as pd
from pandas import DataFrame

from app.utils import ArrayUtil


class TimeSequenceModel:

    @staticmethod
    def __is_first_zero(fail_dataframe) -> bool:
        return fail_dataframe["value"][0] is 0

    @staticmethod
    def __is_non_negative(fail_dataframe) -> bool:
        fail_array = fail_dataframe["value"]
        return len(fail_array[fail_array < 0]) == 0

    @staticmethod
    def __is_incremental(fail_dataframe) -> bool:
        differ_fail_dataframe = TimeSequenceModel.differ_fail(fail_dataframe)
        return TimeSequenceModel.__is_non_negative(differ_fail_dataframe)

    @staticmethod
    def differ_fail(fail_dataframe) -> DataFrame:
        differ_fail_list = np.diff(fail_dataframe["value"]).tolist()
        differ_fail_dataframe = pd.DataFrame({"value": differ_fail_list})
        return differ_fail_dataframe

    @staticmethod
    def prefix_sum_fail(differ_fail_dataframe) -> DataFrame:
        fail_list = list(itertools.accumulate(differ_fail_dataframe["value"].tolist()))
        fail_list.insert(0, 0)
        differ_fail_dataframe = pd.DataFrame({"value": fail_list})
        return differ_fail_dataframe

    @staticmethod
    def is_legal(fail_dataframe) -> bool:
        return TimeSequenceModel.__is_first_zero(fail_dataframe) \
               and TimeSequenceModel.__is_non_negative(fail_dataframe) \
               and TimeSequenceModel.__is_incremental(fail_dataframe)

    @staticmethod
    def dumb_split(fail_dataframe, fold) -> Tuple[DataFrame, DataFrame]:
        experiment, predict = ArrayUtil.split_array(fail_dataframe["value"].tolist(), fold)
        return pd.DataFrame({"value": experiment}), pd.DataFrame({"value": predict})


if __name__ == "__main__":
    df = pd.DataFrame({"value": [1, 2, 3, 5, 5]})
    print(df)
    df = TimeSequenceModel.differ_fail(df)
    print(df)
    print(TimeSequenceModel.prefix_sum_fail(df))
